package com.taotao.job.rpc.invoker;

import com.google.common.base.Preconditions;
import com.taotao.job.rpc.core.invoker.Invoker;
import com.taotao.job.rpc.core.meta.IfaceMeta;
import lombok.extern.slf4j.Slf4j;
import com.taotao.job.rpc.invoker.caller.RemoteCaller;
import com.taotao.job.rpc.core.invoker.InvokerMeta;
import com.taotao.job.rpc.core.invoker.RpcInvokerException;

import java.util.Objects;


/**
 * 远程执行器
 *
 * @author fanbeibei
 * @date 2020/10/31 1:02
 */
@Slf4j
public abstract class AbstractRemoteInvoker implements Invoker {

    protected final RemoteCaller remoteCaller;

    protected AbstractRemoteInvoker(RemoteCaller remoteCaller) {
        this.remoteCaller = remoteCaller;
    }


    @Override
    public <T> T invokeMethod(InvokerMeta invokerMeta, Class<T> expectResultClass) throws RpcInvokerException {
        Preconditions.checkArgument(null != invokerMeta);
        Preconditions.checkArgument(null != expectResultClass);

        //2. 获取远程地址
        String address = getRemoteAddress(invokerMeta.extractIfaceMeta());

        //3.远程调用
        return invokeRemoteMethod(invokerMeta, expectResultClass, address);
    }


    /**
     * 执行远程方法
     *
     * @param invokerMeta
     * @param expectResultClass
     * @param address           ip:port
     * @param <T>
     * @return
     * @throws RpcInvokerException
     */
    public <T> T invokeRemoteMethod(InvokerMeta invokerMeta, Class<T> expectResultClass, String address) throws RpcInvokerException {
        Preconditions.checkArgument(null != invokerMeta);
        Preconditions.checkArgument(null != expectResultClass);
        Preconditions.checkArgument(null != address && !Objects.equals(address.trim(), ""));

        //3.远程调用
        return callRemote(address, invokerMeta, expectResultClass);

    }

    /**
     * 调用远程方法
     *
     * @param address           ip:port
     * @param invokerMeta
     * @param expectResultClass
     * @param <T>
     * @return
     * @throws RpcRemoteException
     */
    protected <T> T callRemote(String address, InvokerMeta invokerMeta, Class<T> expectResultClass) throws RpcRemoteException {
        return remoteCaller.callRemote(address, invokerMeta.extractIfaceMeta(), invokerMeta.getArgs(), expectResultClass, invokerMeta.getTimeoutMillis());

    }


    /**
     * 路由地址
     *
     * @param ifaceMeta
     * @return
     */
    protected abstract String getRemoteAddress(IfaceMeta ifaceMeta);


}
